<template>
  <view>
    <!-- 关联选择器，一级一级的如城市选择 -->
    <!-- 关联选择器，一级一级的如城市选择 -->
    <mxp-popup
      ref="popupRef"
      model="bottom"
      :height="options.height"
      :background="options.background"
      :offsetBottom="options.offsetBottom"
      :toolbarOptions="options.toolbarOptions"
      :showToolbar="options.showToolbar"
      :zIndex="options.zIndex"
      :maskBackground="options.maskBackground"
      :maskClose="options.maskClose"
      @confirm="onConfirm"
    >
      <view style="position: relative; width: 750rpx" :style="{ height: options.height }">
        <view v-if="data.loadState" class="loading-box" :style="{ background: getAmendAlphaColor(options.background, 0.8) }">
          <slot name="loading">
            <mxp-icon name="jiazai" :spin="true" :color="loadingIconColor" size="30px"></mxp-icon>
          </slot>
        </view>
        <view class="header-vessel" :style="{ height: headerHeight }">
          <mxp-tabs
            :list="headerList"
            :current="data.curIndex"
            :activeColor="options.activeColor"
            :color="options.color"
            itemWidth="138rpx"
            @change="headerClick"
          ></mxp-tabs>
          <mxp-line></mxp-line>
        </view>
        <view v-if="data.showPicker" key="view-2" class="picker-view-box-vessel">
          <swiper style="width: 100%" :style="{ height: swiperHeight }" :current="data.curIndex" :skipHiddenItemLayout="true" @change="onSwiperChange">
            <swiper-item v-for="(list1, index) in data.dateList" :key="index" style="width: 100%" :style="{ height: swiperHeight }">
              <slot>
                <mxp-index-list
                  :list="list1"
                  :childItemColor="options.color"
                  :themeColor="options.activeColor"
                  :height="swiperHeight"
                  :labelKey="options.labelKey"
                  :uncheck="false"
                  :multiple="false"
                  :valueKey="options.valueKey"
                  :modelValue="[data.defaultValue[index]?.value]"
                  @change="checkeData"
                ></mxp-index-list>
              </slot>
            </swiper-item>
          </swiper>
        </view>
      </view>
      <slot name="bottom"></slot>
    </mxp-popup>
  </view>
</template>

<script lang="ts" setup>
  import MxpPopup from '../mxp-popup/mxp-popup.vue';
  import MxpLine from '../mxp-line/mxp-line.vue';
  import MxpTabs from '../mxp-tabs/mxp-tabs.vue';
  import type { $ToolbarProps } from '../mxp-toolbar/mxp-toolbar.vue';
  import { computed, nextTick, reactive, ref } from 'vue';
  import MxpIcon from '../mxp-icon/mxp-icon.vue';
  import MxpIndexList, { type $IndexListChildItem } from '../mxp-index-list/mxp-index-list.vue';
  import type { $AllColorStr, $SizeUnitStr } from '../mxp-tool/types/interface';
  import { isObject } from '../mxp-tool/utils/verify';
  import { getAmendAlphaColor } from '../mxp-tool/utils/color';
  import { removeObjectEmpty } from '../mxp-tool/utils/obj';
  import type { SwiperOnChangeEvent } from 'mxp-uni-types';
  import mxpGetSysInfoStore from '../mxp-tool/store/mxp-store-sys-info';

  export type $PopupRelevanceConfirmResult = { valueList: any[]; indexList: number[]; itemList: any[] };
  export type $PopupRelevanceChangeResult = { selected: $PopupRelevanceConfirmResult; levelIndex: number; index: number; label: any; value: any; item: any };
  export type $PopupRelevanceProps = {
    /** 弹出框的高度 */
    height?: $SizeUnitStr; // eslint-disable-line vue/no-unused-properties
    /** 数组 需要展示的数据 */
    list?: unknown[]; // eslint-disable-line vue/no-unused-properties
    /** 当为对象数组时,需要展示的 key,不传则取 valueKey,如果 lvalueKey 也没传则为 'label' */
    labelKey?: number | string; // eslint-disable-line vue/no-unused-properties
    /** 当为对象数组时.需要返回的值的 key，不传则取 labelKey,如果 labelKey 也没传则为 'value' */
    valueKey?: number | string; // eslint-disable-line vue/no-unused-properties
    /** 当为对象数组时.child的 key ,默认为 child */
    childKey?: number | string; // eslint-disable-line vue/no-unused-properties
    /** 背景颜色 */
    background?: $AllColorStr; // eslint-disable-line vue/no-unused-properties
    /** 文本的颜色 */
    color?: $AllColorStr; // eslint-disable-line vue/no-unused-properties
    /** 选中的文本颜色 */
    activeColor?: $AllColorStr; // eslint-disable-line vue/no-unused-properties
    /** header文字的大小 */
    headerFontSize?: $SizeUnitStr; // eslint-disable-line vue/no-unused-properties
    /** 偏移量 （如自定义底部的tabbar就需要一个偏移量） */
    offsetBottom?: $SizeUnitStr; // eslint-disable-line vue/no-unused-properties
    /** 是否留出安全区域 */
    safeSrea?: boolean; // eslint-disable-line vue/no-unused-properties
    /** zIndex */
    zIndex?: number; // eslint-disable-line vue/no-unused-properties
    /** 标题 */
    title?: string; // eslint-disable-line vue/no-unused-properties
    /** 是否显示顶部工具栏 */
    showToolbar?: boolean; // eslint-disable-line vue/no-unused-properties
    /** 顶部工具栏配置项 */
    toolbarOptions?: $ToolbarProps; // eslint-disable-line vue/no-unused-properties
    /** 遮罩的背景色 */
    maskBackground?: $AllColorStr; // eslint-disable-line vue/no-unused-properties
    /** 是否可以点击遮罩关闭 */
    maskClose?: boolean; // eslint-disable-line vue/no-unused-properties
    /** 加载状态图标的颜色 */
    loadingIconColor?: $AllColorStr;
    /** 点击确认按钮，是否自动关闭  */
    autoClose?: boolean; // eslint-disable-line vue/no-unused-properties
    /** 异步获取下一列数据 */
    asyncNextListFun?: (data: $PopupRelevanceChangeResult) => Promise<unknown[]> | unknown[]; // eslint-disable-line vue/no-unused-properties
  };

  export type $CallBack = {
    confirm?: (data: $PopupRelevanceConfirmResult) => void;
    change?: (data: $PopupRelevanceChangeResult) => void;
  };
  export type $Options = $CallBack & $PopupRelevanceProps;

  defineOptions({
    name: 'mxp-popup-relevance',
  });
  const props = withDefaults(defineProps<$PopupRelevanceProps>(), {
    height: undefined as $SizeUnitStr | undefined,
    background: '#ffffff',
    offsetBottom: '0px',
    showSecond: false,
    safeSrea: true,
    zIndex: 888,
    title: '请选择',
    toolbarOptions: () => ({}),
    list: () => [],
    labelKey: undefined as number | string | undefined,
    valueKey: undefined as number | string | undefined,
    childKey: 'child',
    showToolbar: true,
    color: '#333333',
    activeColor: '#3c9cff',
    headerFontSize: '14px',
    maskBackground: undefined as $AllColorStr | undefined,
    maskClose: undefined as boolean | undefined,
    loadingIconColor: '#3c9cff',
    autoClose: true,
    asyncNextListFun: undefined,
  });
  defineSlots<{
    /** 弹出框主体内容 */
    loading: () => void;
    /** 弹出框头部的内容 */
    default: () => void;
    /** 自定义在弹出框外的内容 */
    bottom: () => void;
  }>();

  const popupRef = ref<InstanceType<typeof MxpPopup> | null>(null);
  const options = ref<$CallBack & Required<$PopupRelevanceProps>>(JSON.parse(JSON.stringify(props)));

  const data = reactive({
    loadState: false,
    showPicker: false,
    isSubmit: true,
    dateList: [] as unknown[][],
    curIndex: 0,
    defaultValue: [] as $IndexListChildItem[],
  });
  const headerHeight = '44px';
  const swiperHeight = computed<`calc(${string})`>(() => `calc(${options.value.height} - ${headerHeight} - ${options.value.toolbarOptions?.height || '60px'})`);
  const headerList = computed(() => {
    const list: string[] = [];
    data.defaultValue.forEach((item) => {
      list.push(item.label);
    });
    if (data.dateList.length > data.defaultValue.length) {
      list.push('请选择');
    }
    return list;
  });

  /** 显示 */
  function show(param: $Options = {}) {
    data.loadState = false;
    data.isSubmit = true;
    data.defaultValue = [];
    data.curIndex = 0;
    initData(param);
    popupRef.value?.show({
      confirm() {
        if (data.isSubmit) {
          typeof options.value.confirm === 'function' && options.value.confirm(getSubmitDataFun());
          options.value.autoClose && hide();
        }
      },
    });
    data.showPicker = false;
    setTimeout(() => {
      data.showPicker = true;
    }, 10);
  }

  /**
   * 隐藏
   */
  function hide() {
    popupRef.value?.hide();
  }

  /**
   * 初始化数据
   */
  function initData(param: $Options = {}) {
    data.curIndex = 0;
    const sys = mxpGetSysInfoStore().getSysInfo();
    const op: $Options = { ...props, ...removeObjectEmpty(param) };
    op.height = op.height || `${Math.fround(sys.value.windowHeight * 0.8)}px`;
    const haveLabelKey = ['string', 'number'].includes(typeof op.labelKey);
    const haveValueKey = ['string', 'number'].includes(typeof op.valueKey);
    op.labelKey = haveLabelKey ? op.labelKey : haveValueKey ? op.valueKey : 'label';
    op.valueKey = haveValueKey ? op.labelKey : haveLabelKey ? op.valueKey : 'value';
    if (!op.toolbarOptions) {
      op.toolbarOptions = { title: op.title };
    } else {
      op.toolbarOptions!.title = op.title;
    }
    data.dateList.push(op.list || []);
    options.value = op as $CallBack & Required<$PopupRelevanceProps>;
  }

  /**
   * 从列表中选中某一项
   */
  async function checkeData(item: { currInfo: $IndexListChildItem; selected: any }) {
    const childKey = options.value.childKey;
    data.defaultValue = [...data.defaultValue.splice(0, data.curIndex), item.currInfo];
    data.dateList = [...data.dateList.splice(0, data.curIndex + 1)];
    const submitData = getSubmitDataFun();
    const res: $PopupRelevanceChangeResult = {
      selected: submitData,
      levelIndex: data.curIndex,
      index: item.currInfo.index,
      label: item.currInfo.label,
      value: item.currInfo.value,
      item: item.currInfo.item,
    };
    typeof options.value.change === 'function' && options.value.change(res);

    if (typeof options.value.asyncNextListFun === 'function') {
      try {
        data.loadState = true;
        const list = await options.value.asyncNextListFun(res);
        list.length > 0 && data.dateList.push(list);
        data.loadState = false;
      } catch (e) {
        data.loadState = false;
        console.error('请求出错', e);
      }
    } else if (
      data.curIndex + 1 >= data.defaultValue.length &&
      isObject(item.currInfo.item) &&
      childKey in item.currInfo.item &&
      Array.isArray(item.currInfo.item[childKey])
    ) {
      data.dateList.push(item.currInfo.item[childKey] as unknown[]);
    }

    nextTick(() => {
      const defLen = data.defaultValue.length;
      const dataLen = data.dateList.length;
      data.curIndex = data.curIndex < dataLen - 1 ? defLen : dataLen - 1;
    });
  }

  /**
   * 点击 header,切换 swiper
   */
  function headerClick(index: number) {
    data.curIndex = index;
  }

  /**
   * swiper发生变化
   */
  function onSwiperChange(event: SwiperOnChangeEvent) {
    data.curIndex = event.detail.current;
  }
  /**
   * 点击确定
   */
  function onConfirm() {
    if (data.isSubmit && !data.loadState) {
      typeof options.value.confirm === 'function' && options.value.confirm(getSubmitDataFun());
      options.value.autoClose && hide();
    }
  }

  /**
   * 得到最终需要返回的数据
   */
  function getSubmitDataFun(): $PopupRelevanceConfirmResult {
    const valueList: any[] = [];
    const indexList: number[] = [];
    const itemList: any[] = [];
    data.defaultValue.forEach((item) => {
      valueList.push(item.value);
      indexList.push(item.index);
      itemList.push(item.item);
    });
    return { valueList, indexList, itemList };
  }

  /** 设置加载状态 */
  function setLoadState(state: boolean) {
    data.loadState = Boolean(state);
  }

  defineExpose({
    /** 显示 */
    show,
    /** 隐藏 */
    hide,
    /** 提交 */
    confirm,
    /** 设置加载状态 */
    setLoadState,
  });
</script>

<style lang="scss" scoped>
  .loading-box {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    z-index: 9999;
    display: flex;
    flex-flow: column nowrap;
    align-items: center;
    justify-content: center;
    height: 100%;
  }

  .header-box {
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
    justify-content: flex-start;
    width: 100%;
    height: 100%;
    padding: 0 5px;

    .header-text-box {
      position: relative;
      display: flex;
      flex-flow: column nowrap;
      align-items: center;
      justify-content: center;
      height: 100%;
      padding: 0 10px;

      .header-text {
        font-size: 14px;
        transition: color 0.2s;
      }

      .line {
        position: absolute;
        right: 10px;
        bottom: 1px;
        left: 10px;
        height: 2px;
        border-radius: 2px;
      }
    }
  }

  .item-box {
    padding: 10px 15px;

    .item-text {
      font-size: 14px;
      transition: color 0.2s;
    }
  }
</style>
